/*
Copyright (C) 1996-1997 GX Media, Inc.
Copyright (C) 2010 Ronie Salgado

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

#ifndef QVIEW_H
#define QVIEW_H

#include "LCommon.h"
#include "QooleDoc.h"
#include "View.h"
#include "QooleOp.h"

class QDraw;
class QViewsState;
class QView: public wxView
{
	DECLARE_DYNAMIC_CLASS(QView);
public:
	enum ViewType
	{
		VT_TOP = 0,
		VT_3D,
		VT_BACK,
		VT_SIDE
	};

	enum RenderType
	{
		RT_WIREFRAME = 0,
		RT_SOLID,
		RT_TEXTURED,
		RT_SHADED,
	};

	QView();
	~QView();

	// Document.
	QooleDoc *GetDocument()
	{ return static_cast<QooleDoc*> (wxView::GetDocument());}

	// Quad views support.
	wxWindow *GetParentFrame();
	void SetParentFrame(wxWindow *parent);

	wxWindow *GetViewFrame();
	const wxWindow *GetViewFrame() const;

	// Qoole view.
	View *GetViewPtr()
	{ return view; }
	const View *GetViewPtr() const
	{ return view; }

	// View type.
	ViewType GetViewType() const
	{ return viewType; }
	// QView Init stuff.
	void InitView(int id, Object *viewScope,
				  Selector *selector, const Vector3d &posVec);
	void CreateQDraw(void);
	void SetColors(void);
	void SelColors(int vrc, int red, int green, int blue);
	void SuspendRenderLib(bool suspend);

	// Used by QMainFrame to control changes in QViews during undo/redo.
	void GetViewState(Vector3d &posVec, SphrVector &oriVec,
					  float &zoomRate, ViewType *viewType = NULL) const;
	void SetViewState(const Vector3d &posVec, const SphrVector &oriVec,
					  float zoomRate, bool updateView = false);

	// Op mode changed.
	void OnOpModeChanged(OperationMode opMode, OperationMode prevOpMode);

	// Change to fly through mode.
	void OnStartFlyThrough(void);

	// Display face selection. Used by texture property sheet.
	void RenderSelectedFace(bool visible);

	// Grids display.
	static void UpdateGridsDisplay();

	// wxView events.
	virtual bool OnCreate(wxDocument* doc, long flags);
	virtual bool OnClose(bool deleteWindow = true);
	virtual void OnSize(const wxSize &newSize);
	virtual void OnDraw(wxDC* dc);
	virtual void OnUpdate(wxView* sender, wxObject* hint = NULL);

	// Operation position.
	static const Vector3d &GetOperateCenterPos(void);
	static void SetOperateCenterPos(const Vector3d &opCenterPos);
	void UpdateSizeInfo();

	// Snap the object add position.
	void SnapAddObjPos(Vector3d &addVec);

	// Init and global settings.
	static void Init();
	static void Exit();

	// Re-init render library.
	static void RefreshAll();

	// Config stuff.
	static LConfig *cfg;
	static bool invLMouse, invRMouse;
	static unsigned int walkSpeed, sensitivity;
	static unsigned int keyForward, keyBackward;
	static unsigned int keyLeft, keyRight, keyUp, keyDown;
	static unsigned int snapAlignment;
	static unsigned int editConstraint;
	static unsigned int dragThreshold;

	static wxString draw2dWire;
	static wxString draw3dWire;
	static wxString draw3dSolid;
	static wxString draw3dTex;

	DECLARE_EVENT_TABLE();
protected:
	// Event handlers.
	void OnContextMenu(wxContextMenuEvent &event);
	void OnLButtonDown(wxMouseEvent &event);
	void OnLButtonUp(wxMouseEvent &event);
	void OnMButtonDown(wxMouseEvent &event);
	void OnMButtonUp(wxMouseEvent &event);
	void OnRButtonDown(wxMouseEvent &event);
	void OnRButtonUp(wxMouseEvent &event);
	void OnMouseMove(wxMouseEvent &event);
	void OnMouseWheel(wxMouseEvent &event);
	void OnKeyUp(wxKeyEvent &event);
	void OnKeyDown(wxKeyEvent &event);
	void OnChar(wxKeyEvent &event);

	void OnEditPaste(wxCommandEvent &event);
	void OnEditPasteUI(wxUpdateUIEvent &event);
	void OnEditDuplicate(wxCommandEvent &event);
	void OnEditDuplicateUI(wxUpdateUIEvent &event);
	void OnEditIncrGridSize(wxCommandEvent &event);
	void OnEditDecrGridSize(wxCommandEvent &event);
	void OnEditAlignSet(wxCommandEvent &event);
	void OnEditAlignSelection(wxCommandEvent &event);
	void OnEditAlignUI(wxUpdateUIEvent &event);

	void OnRenderWireFrame(wxCommandEvent &event);
	void OnRenderWireFrameUI(wxUpdateUIEvent &event);
	void OnRenderSolid(wxCommandEvent &event);
	void OnRenderSolidUI(wxUpdateUIEvent &event);
	void OnRenderTextured(wxCommandEvent &event);
	void OnRenderTexturedUI(wxUpdateUIEvent &event);
	void OnRenderShaded(wxCommandEvent &event);
	void OnRenderShadedUI(wxUpdateUIEvent &event);
	void SetRenderType(RenderType rt);

protected:
	// Screen drawing stuff.
	void DrawOpCenter(void);
	void DrawDragBox(void);
	void DrawScaleBoundBox(void);
	void CalcScaleManipDots(void);
	void DrawOpPlane(void);
	void DrawCutSide(void);

	// Used to resize view clip regions.
	void OnZoomChanged(void);

	// Adjust the views.
	void OnScopeChanged(Object *pOldScope);

	// Conversion between device and logical coords.
	void DC2LC(const wxPoint &pt, float &x, float &y) const;
	void DU2LU(const wxPoint &pt, float &x, float &y) const;
	void LC2DC(float x, float y, wxPoint &pt) const;
	void LC2DC(const Vector3d &vec3D, wxPoint &pt) const;
	void LU2DU(float x, float y, wxPoint &pt) const;

	// Context Menu.
	void OnRMBUContextMenu(wxMouseEvent &event);

	// Handle the mouse interface in QViews
	//  for the different op modes.
	void OnQViewScrollView(wxTimerEvent &event);

	// Timer Render.  Need to be changed to On Idle Render.
	void SetTimerUpdateQViews(bool set);
	void OnTimerUpdateQViews(wxTimerEvent &event);

	// Selection.
	void OnLMBDObjectsSelect(wxMouseEvent &event);
	void OnMMObjectsSelect(wxMouseEvent &event);
	void OnLMBUObjectsSelect(wxMouseEvent &event);
	void OnUpdateDragSelect(wxTimerEvent &event);

	// Snapping.
	void SetSnapScope(Object &snapScope);
	Vector3d &SnapVector2World(Vector3d &snapVec,
							   const Vector3d *pLockVector = NULL);

	// OpCenter.
	void FindOpCenterPos(wxPoint &opCenterPos, Vector3d *pCenterVec = NULL);
	void DragOpCenterPos(wxPoint point, bool updateView = true);

	// Move / Rotate / Scale
	void OnLMBDObjectsMoveRotateScale(wxMouseEvent &event);

	void OnMMObjectsMove(wxMouseEvent &event);
	void OnLMBUObjectsMove(wxMouseEvent &event);

	void OnMMObjectsRotate(wxMouseEvent &event);
	void OnLMBUObjectsRotate(wxMouseEvent &event);

	void OnMMObjectsScale(wxMouseEvent &event);
	void OnLMBUObjectsScale(wxMouseEvent &event);

	void OnLMBDObjectsMultiTool(wxMouseEvent &event);
	void OnMMObjectsMultiTool(wxMouseEvent &event);
	void OnLMBUObjectsMultiTool(wxMouseEvent &event);

	// Brush Modify.
	void UpdateManipDispStat(void);
	void OnLMBDModifyBrush(wxMouseEvent &event);
	void OnMMModifyBrush(wxMouseEvent &event);
	void OnLMBUModifyBrush(wxMouseEvent &event);

	// Plane Cut, Mirror / Flip
	void OnLMBDDefineOpPlane(wxMouseEvent &event);
	void OnLMBUDefineOpPlane(wxMouseEvent &event);
	void OnMMDefineOpPlane(wxMouseEvent &event);
	void OnRMBDDefineOpPlane(wxMouseEvent &event);

	Plane CalcOpPlane(void);

	// Eye movements.
	void ReCenterMousePos(wxPoint &ptMousePos);
	void SetTimerUpdateLockedQViews(bool set, wxMouseEvent &mevent);
	void OnTimerUpdateLockedQViews(wxTimerEvent &event);

	void OnMBDEyeMoveRotateZoom(wxMouseEvent &event);
	void OnMBUEyeMoveRotateZoom(wxMouseEvent &event);

	void OnLMBEyeMove(wxMouseEvent &event);
	void MoveEyeView(const Vector3d &moveVec);
	void OnEndViewMove(wxTimerEvent &event);

	void OnRMBEyeZoom(wxMouseEvent &event);
	void ZoomEyeView(float depthVal);
	void OnViewZoomIn(void);
	void OnViewZoomOut(void);

	void OnLMBEyeRotate(wxMouseEvent &event);
	void OnRMBEyeRotate(wxMouseEvent &event);

	void UpdateCoordInfo(wxPoint coord);

	void OnKeyCheckFlyThrough(bool forceUpdate = false);
	void OnMMFlyThrough(wxMouseEvent &event);

	// Timer creation.
	void CreateTimers();

protected:
	wxWindow *parentFrame;
	wxWindow *viewFrame;

	ViewType viewType;
	RenderType renderType;
	View *view;
	QDraw *draw;

	float zoomVal;
	int width, height;
	int orgX, orgY;

	int bits;

	wxRect dragBoxRect;

	bool useBack;
	Vector3d oldViewPos;
	SphrVector oldOrient;
	Object *oldViewObj;
	float oldZoomVal;

	LinkList<ObjectPtr> selectObjectsBuffer, oldSelection;
	Vector3d downClickVec, upClickVec;
	QViewsState *qviewsBefore;

	wxPoint	ptClick, lastMPos, scrollPos;
	bool	mouseLClick, mouseMClick, mouseRClick;
	bool	mouseLDrag, mouseMDrag, mouseRDrag;
	bool	reverseSelect;
	bool	selectPending, selectAddPending;
	bool	dragSelect, dragAddSelect;
	bool	operatePending, dragOperate, dragOpCenter;
	bool	dragScaleManipDot;
	bool	snapCorner;
	OperationMode subOperationMode;
	unsigned int scrollingView;

	static bool	drawScaleBoundBox;
	static bool updateSclBoundBox;
	Vector3d scaleManipDots[8];

	static Vector3d opCenterVec, oldOpCenterVec;
	static Vector3d opCornerVec;
	static unsigned int modifyBrushMode;
	static const GPolygon *pManipFace;
	static const Edge3d *pManipEdge;
	static int manipVertex;
	static bool dispManipDots;

	bool	planeDefined;
	int		clipSide;   // Left = -1, Split = 0, Right = 1.
	int		dragPlanePt;
	Vector3d planeDragPt1, planeDragPt2;
	wxBitmap scissors;

	Vector3d tempSnapVec, tempSnapVecTtl;
	Vector3d tempSnapBoundVec1, tempSnapBoundVec2;
	Vector3d tempScaleVec;
	Matrix44 tempSnapMatrix, tempSnapInvMatrix;
	Matrix44 tempInvViewMatrix;
	float tempSnapRotVal, tempLastSnapRotVal;

	int flyTime;

	// The different timers used.
	wxTimer timerUpdateDragSel;
	wxTimer timerScrollView;
	wxTimer timerRenderViews;
	wxTimer timerRenderLockedViews;
	wxTimer timerUpdateViews;
};

#endif //QVIEW_H
